package io.jft.doll.ui.room

import android.arch.lifecycle.ViewModelProviders
import android.content.Context
import android.content.Intent
import android.databinding.ObservableField
import android.media.AudioManager
import android.media.SoundPool
import android.os.Bundle
import android.os.CountDownTimer
import android.support.v7.app.AlertDialog
import android.view.View
import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.g.base.extend.observeEx
import com.g.base.extend.resultNotNull
import com.g.base.extend.setTimeout
import com.g.base.extend.toast
import com.g.base.help.ioResultToMainThread
import com.g.base.help.observeSimpleNotify
import com.g.base.room.entity.UserEntity
import com.g.base.room.repository.Status
import com.g.base.router.RouteExtras
import com.g.base.ui.BaseActivity
import com.steam.video.Player
import com.steam.video.SteamStatus
import com.steam.video.VideoListener
import io.jft.doll.R
import io.jft.doll.databinding.ActivityRoomBinding
import io.jft.doll.event.AppointmentCleanEvent
import io.jft.doll.event.NotifyUrl
import io.jft.doll.model.viewModel.RoomViewModel
import io.jft.doll.model.viewModel.UserViewModel
import io.jft.doll.room.entity.common.RoomCEntity
import io.jft.doll.router.RouterPage
import io.jft.doll.tcp.TcpC
import io.jft.doll.tcp.TcpHelp
import io.jft.doll.tcp.event.TcpData
import io.jft.doll.tcp.tcpClient
import io.netty.buffer.ByteBuf
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.net.InetAddress

/**
 * Created by G on 2017/12/20 0020.
 */
@Route(path = RouterPage.RoomActivity, extras = RouteExtras.NeedOauth)
class RoomActivity : BaseActivity<ActivityRoomBinding>(), VideoListener {
    override var isFullScreen: Boolean = true

    private val roomDetailFragment by lazy { RoomDetailFragment() }
    private val userViewModel by lazy { ViewModelProviders.of(this).get(UserViewModel::class.java) }
    private val roomViewModel by lazy { ViewModelProviders.of(this).get(RoomViewModel::class.java) }
    private val soundPool = SoundPool(3, AudioManager.STREAM_MUSIC, 0)
    private var soundIdMap = HashMap<Int, Int>()
    private var isActive = false

    @Autowired
    @JvmField
    var roomId: String = ""
    @Autowired
    @JvmField
    var token: ByteArray? = null

    private var gameTimeCountDown: CountDownTimer? = null
    private var gameWaitResultTimeout: (() -> Unit)? = null

    private var steamStatus = SteamStatus.destroy
    val isPlayModel = ObservableField(false)
    val isAppointment = ObservableField(true)
    val gameTime = ObservableField("30")
    var remaining = ObservableField("0")
    val paying = ObservableField("0")
    var queue = ObservableField(0)

    private var roomData: RoomCEntity? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_room)
        if (getSharedPreferences("setting", Context.MODE_PRIVATE).getBoolean("roomSound", true))
            playSound(1, "room_bg.mp3", -1)
        setup()
        contentView.back.setOnClickListener { onBackPressed() }
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
        setup()
    }

    override fun supportSlideBack(): Boolean {
        return !(isPlayModel.get() ?: false)
    }

    override fun onReload() {
        getData()
    }

    override fun onTokenChange(data: UserEntity?) {
        if (data == null)
            showNeedOauth()
        else
            getData()
    }

    private fun setup(isCleanToken: Boolean = false) {
        ARouter.getInstance().inject(this)

        //无效保护
        if (roomId.isEmpty()) {
            toast("无效的房间号")
            finishAfterTransition()
            return
        }

        isPlayModel.set(!isCleanToken && token != null)
        roomViewModel.roomId = roomId
        roomData = null
        supportFragmentManager.beginTransaction()
                .replace(R.id.roomDetail, roomDetailFragment)
                .commitAllowingStateLoss()

        //获取数据
        getData()
        obsData()
        contentView.data = this
    }

    //返回保护
    override fun onBackPressed() {
        if (isPlayModel.get() == true) {
            AlertDialog.Builder(this)
                    .apply {
                        setTitle("Tip")
                        setMessage("您正在玩游戏中,确定要退出吗?")
                        setNegativeButton("我再想想", null)
                        setPositiveButton("确定") { dialog, _ ->
                            dialog.dismiss()
                            finishAfterTransition()
                        }
                        show()
                    }
        } else {
            finishAfterTransition()
        }
    }

    private fun obsData() {
        observeSimpleNotify<Any?>(this, NotifyUrl.UserRemaining) {
            userViewModel.operateRemain(true)
            true
        }

        userViewModel.obsRemainingSum()
                .resultNotNull()
                .observeEx(this) {
                    when (it.status) {
                        Status.Loading -> remaining.set("--")
                        Status.Content -> remaining.set(it.data!!)
                        Status.Error -> remaining.set("??")
                    }
                }

        userViewModel.obsRoomDetail()
                .resultNotNull()
                .observeEx(this) {
                    when (it.status) {
                        Status.Loading -> showLoading()
                        Status.Content -> {
                            val roomData = it.data!!

                            if (roomData.status >= 2) {
                                toast("本房间维护中~")
                                finishAfterTransition()
                                return@observeEx
                            }

                            queue.set(roomData.queued)
                            paying.set(roomData.paying)
                            isAppointment.set(roomData.isAppointment)
                            //重置数据
                            gameTimeCountDown?.cancel()
                            gameWaitResultTimeout?.invoke()
                            gameTimeCountDown = null
                            gameWaitResultTimeout = null
                            if (isPlayModel.get()!!) {
                                gameTimeCountDown = CountDownGame(roomData.gameTime * 1000L)
                                //开始倒计时
                                gameTimeCountDown?.start()
                            }
                            //DNS解析
                            ioResultToMainThread(
                                    {
                                        roomData.udp.address1 = InetAddress.getByName(roomData.udp.address1).hostAddress
                                        roomData.udp.address2 = InetAddress.getByName(roomData.udp.address2).hostAddress
                                    },
                                    {
                                        this.roomData = roomData
                                        videoInit()
                                        showContentView()
                                    }
                            )
                        }
                        Status.Error -> {
                            showError("加载房间数据时出现错误")
                        }
                    }
                }
    }

    private fun getData() {
        userViewModel.operateRemain()
        userViewModel.operateRoomDetail(roomId)
    }

    /**
     * 只有在初始化状态允许
     */
    private fun videoInit() {
        roomData?.also {
            contentView.video.getSurface()
                    .subscribe(
                            { surface ->
                                if (isPlayModel.get() == true)
                                    Player.createTCP(surface, it.udp.address1, it.udp.address1, it.udp.port1, it.udp.port2, this)
                                else
                                    Player.createRTMP(surface, it.rtmp.address1, it.rtmp.address2, this)
                                Player.startPlay()
                            },
                            {
                                toast("获取视频窗口超时~!")
                                finishAfterTransition()
                            }
                    )
        }
    }

    /**
     * 视频状态改变
     */
    override fun onChange(status: Int) {
        runOnUiThread {
            steamStatus = status
            when (status) {
                SteamStatus.destroy -> {
                    contentView.video.showStop()
                    if (isActive) setTimeout { Player.startPlay() }
                }
                SteamStatus.resuming -> {
                    contentView.video.showLoading()
                }
                SteamStatus.resume -> {
                    contentView.video.showNothing()
                }
            }
        }
    }

    fun onFeedBackClick(view: View) {
        ARouter.getInstance().build(RouterPage.GameHistoryActivity).withString("roomId", roomId).navigation(this)
    }

    fun onRechargeClick(view: View) {
        ARouter.getInstance().build(RouterPage.RechargeActivity).navigation(this)
    }

    fun onSwitchVideoClick(view: View) {
        Player.switchSteam()
        playSound(2, "click.mp3", 0, 3)
    }

    fun onVideoClick(view: View) {
        if (steamStatus == SteamStatus.destroy) {
            videoInit()
        } else if (steamStatus == SteamStatus.pause) {
            Player.startPlay()
        }
    }

    fun onMainButtonClick(view: View) {
        TcpHelp.appointmentRoom(roomId, !isAppointment.get()!!)
        playSound(2, "click.mp3", 0, 3)
    }

    fun onActionClick(view: View) {
        token ?: return
        val isPlaySteam2 = Player.activeIndexSteam() == 1
        val data: ByteBuf = tcpClient.createBuffer().writeBytes(token)
                .writeByte(when (view.id) {
                    R.id.actionLeft -> if (isPlaySteam2) 0x04 else 0x01
                    R.id.actionRight -> if (isPlaySteam2) 0x02 else 0x03
                    R.id.actionUp -> if (isPlaySteam2) 0x01 else 0x02
                    R.id.actionDown -> if (isPlaySteam2) 0x03 else 0x04
                    R.id.actionDone -> 0x00
                    else -> 0x05
                })

        tcpClient.writeAndFlush(TcpData(TcpC.COMD_OPERATE, data)) {
            if (view.id == R.id.actionDone) {
                if (it.isEmpty()) {
                    tcpClient.writeAndFlush(TcpData(TcpC.COMD_OPERATE, data)) { tcpClient.writeAndFlush(TcpData(TcpC.COMD_OPERATE, data)) {} }
                    startWaitAmountTimeout()
                } else {
                    toast("下爪子失败~")
                }
            }
        }
    }

    fun onActionTouchDownClick(view: View) {
        playSound(2, "click.mp3", 0, 3)
    }

    //等待返回数量 的超时处理
    fun startWaitAmountTimeout() {
        if (gameWaitResultTimeout != null) return
        gameWaitResultTimeout = setTimeout(20000L) {
            if (isPlayModel.get() == true) {
                TcpHelp.onAmountReturn(-1)
            }
        }
        toast("处理游戏结果中~")
        playSound(3, "electrification.mp3", 0, 2)
    }

    override fun onResume() {
        super.onResume()
        isActive = true
        contentView.video.startRender()
        Player.startPlay()
        soundPool.autoResume()
    }

    override fun onPause() {
        super.onPause()
        isActive = false
        contentView.video.stopRender()
        Player.stopPlay()
        soundPool.autoPause()
    }

    override fun onDestroy() {
        super.onDestroy()
        Player.destroy()
        gameTimeCountDown?.cancel()
        gameWaitResultTimeout?.invoke()
        soundIdMap.forEach {
            if (it.value != 0)
                soundPool.unload(it.value)
        }
        soundPool.release()
        contentView.video.release()
    }

    private fun playSound(key: Int, name: String, loop: Int, priority: Int = 1, retryCount: Int = 4) {
        if (retryCount <= 0) return
        val id = soundIdMap[key] ?: 0
        if (id != 0) {
            soundPool.play(id, 1f, 1f, priority, loop, 1f)
        } else {
            soundIdMap[key] = soundPool.load(assets.openFd(name), 1)
            soundPool.setOnLoadCompleteListener { _, sampleId, status ->
                if (sampleId == soundIdMap[key] && status != 0)
                    soundIdMap[key] = 0
                playSound(key, name, loop, priority, retryCount - 1)
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onAppointmentClean(ev: AppointmentCleanEvent) {
        if (isPlayModel.get() == true)
            setup(true)
    }

    inner class CountDownGame(gameTime: Long) : CountDownTimer(gameTime, 1000L) {
        override fun onFinish() {
            //触发超时
            startWaitAmountTimeout()
        }

        override fun onTick(p0: Long) {
            //倒计时
            gameTime.set((p0 / 1000L).toString())
        }
    }
}